package ch.zbw.timeline.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import ch.zbw.timeline.domain.DailyPresence;
import ch.zbw.timeline.domain.Holiday;
import ch.zbw.timeline.domain.Period;
import ch.zbw.timeline.domain.YearConfig;
import ch.zbw.timeline.repository.DailyPresenceRepository;
import ch.zbw.timeline.repository.YearConfigRepository;
import ch.zbw.timeline.repository.hibernate.HibernateDailyPresenceRepository;
import ch.zbw.timeline.repository.hibernate.HibernateYearConfigRepository;

/**
 * Class that implements the YearConfigService-Interface to handle the
 * yearConfigs
 * 
 * @author Marco Ramseyer
 * @version 25.12.2011
 * 
 */
public class ZbwYearConfigService implements YearConfigService {

	private YearConfigRepository yearConfigRepository;
	private DailyPresenceRepository dailyPresenceRepository;
	private HolidayService holidayService;

	/**
	 * Default Constructor to create the yearConfigRepository and the
	 * dailyPresenceRepository
	 */
	public ZbwYearConfigService() {
		// yearConfigRepository = new MockYearConfigRepository();
		// dailyPresenceRepository = new MockDailyPresenceRepository();
		holidayService = new ZbwHolidayService();

		yearConfigRepository = new HibernateYearConfigRepository();
		dailyPresenceRepository = new HibernateDailyPresenceRepository();
	}

	/**
	 * Constructur with parameters initiates a new yearConfigRepository
	 * 
	 * @param yearConfigRepository
	 */
	public ZbwYearConfigService(YearConfigRepository yearConfigRepository) {
		this.yearConfigRepository = yearConfigRepository;
	}

	/*
	 * (non-Javadoc)
	 * @see ch.zbw.timeline.service.YearConfigService#createYearConfig(int, int, double, double, int, java.util.Calendar)
	 */
	@Override
	public YearConfig createYearConfig(int year, int periodLength,
			double weeklyWorkingHours, double flexitimePercent,
			int numberOfVacationDay, Calendar easterSunday) {

		boolean count = false;

		List<YearConfig> yearConfRepTmp = yearConfigRepository
				.getAllYearConfigs();

		for (int i = 0; i < yearConfRepTmp.size(); i++) {

			if (yearConfRepTmp.get(i).getYear() == year) {

				isYearUsed(yearConfRepTmp.get(i).getId());
				if (isYearUsed(yearConfRepTmp.get(i).getId())) {
					count = true;
				}
			}
		}

		if (count) {
			return null;
		} else {

			YearConfig yearConfig = new YearConfig();
			yearConfig.setYear(year);
			yearConfig.setPeriodLength(periodLength);
			yearConfig.setWeeklyWorkingHours(weeklyWorkingHours);
			yearConfig.setFlexitimePercent(flexitimePercent);
			yearConfig.setNumberOfVacationDay(numberOfVacationDay);
			yearConfig
					.setEasterSunday(new Date(easterSunday.getTimeInMillis()));

			return yearConfigRepository.saveYearConfig(yearConfig);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see ch.zbw.timeline.service.YearConfigService#saveYearConfig(ch.zbw.timeline.domain.YearConfig)
	 */
	@Override
	public YearConfig saveYearConfig(YearConfig yearConfig) {

		boolean count = false;

		List<YearConfig> yearConfRepTmp = yearConfigRepository
				.getAllYearConfigs();

		for (int i = 0; i < yearConfRepTmp.size(); i++) {

			if (yearConfRepTmp.get(i).getYear() == yearConfig.getYear()) {

				if (isYearUsed(yearConfRepTmp.get(i).getId())) {
					count = true;
				}
			}
		}

		if (count) {
			return null;
		} else {

			List<Holiday> holidays = yearConfig.getHolidays();
			if (holidays != null) {
				for (Holiday h : holidays) {
					if (h.isActive()) {
						holidayService.saveHoliday(h);
					} else {
						holidayService.deleteHoliday(h, yearConfig);
					}
				}
			}

			yearConfig
					.setHolidays(holidayService.getHolidaysByYear(yearConfig));
			return yearConfigRepository.saveYearConfig(yearConfig);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see ch.zbw.timeline.service.YearConfigService#getAllYearConfigs()
	 */
	@Override
	public List<YearConfig> getAllYearConfigs() {
		List<YearConfig> configs = yearConfigRepository.getAllYearConfigs();
		for (YearConfig y : configs) {
			y.setHolidays(holidayService.getHolidaysByYear(y));
		}
		return configs;
	}

	/*
	 * (non-Javadoc)
	 * @see ch.zbw.timeline.service.YearConfigService#isYearUsed(int)
	 */
	@Override
	public boolean isYearUsed(int yearId) {

		List<DailyPresence> listTmp = new ArrayList<DailyPresence>();
		listTmp = dailyPresenceRepository.getDailyPresenceByYearId(yearId);

		if (listTmp != null && listTmp.size() > 0) {
			return true;
		} else {
			return false;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see ch.zbw.timeline.service.YearConfigService#getAllPeriodsByYearConfig(ch.zbw.timeline.domain.YearConfig)
	 */
	@Override
	public List<Period> getAllPeriodsByYearConfig(YearConfig yearConfig) {
		if (yearConfig != null) {

			List<Period> tempList = new ArrayList<Period>();
			int year = yearConfig.getYear();
			int periodLength = yearConfig.getPeriodLength();

			GregorianCalendar date = new GregorianCalendar();
			boolean leapYear = date.isLeapYear(year);

			switch (periodLength) {
			case 12:
				Period period = createPeriod(year, Calendar.JANUARY, 1,
						Calendar.DECEMBER, 31);

				tempList.add(period);
				break;

			case 6:
				Period period1 = createPeriod(year, Calendar.JANUARY, 1,
						Calendar.JUNE, 30);
				Period period2 = createPeriod(year, Calendar.JULY, 1,
						Calendar.DECEMBER, 31);

				tempList.add(period1);
				tempList.add(period2);
				break;
			case 4:
				Period period3 = createPeriod(year, Calendar.JANUARY, 1,
						Calendar.APRIL, 30);
				Period period4 = createPeriod(year, Calendar.MAY, 1,
						Calendar.AUGUST, 31);
				Period perido5 = createPeriod(year, Calendar.SEPTEMBER, 1,
						Calendar.DECEMBER, 31);

				tempList.add(period3);
				tempList.add(period4);
				tempList.add(perido5);
				break;
			case 3:
				Period period6 = createPeriod(year, Calendar.JANUARY, 1,
						Calendar.MARCH, 31);
				Period period7 = createPeriod(year, Calendar.APRIL, 1,
						Calendar.JUNE, 31);
				Period perido8 = createPeriod(year, Calendar.JULY, 1,
						Calendar.SEPTEMBER, 30);
				Period period9 = createPeriod(year, Calendar.OCTOBER, 1,
						Calendar.DECEMBER, 31);

				tempList.add(period6);
				tempList.add(period7);
				tempList.add(perido8);
				tempList.add(period9);
				break;
			case 2:
				Period period10 = null;
				if (leapYear) {
					period10 = createPeriod(year, Calendar.JANUARY, 1,
							Calendar.FEBRUARY, 29);
					tempList.add(period10);

				} else {
					period10 = createPeriod(year, Calendar.JANUARY, 1,
							Calendar.FEBRUARY, 28);
					tempList.add(period10);

				}
				Period period11 = createPeriod(year, Calendar.MARCH, 1,
						Calendar.APRIL, 30);
				Period perido12 = createPeriod(year, Calendar.MAY, 1,
						Calendar.JUNE, 31);
				Period period13 = createPeriod(year, Calendar.JULY, 1,
						Calendar.AUGUST, 31);
				Period period14 = createPeriod(year, Calendar.SEPTEMBER, 1,
						Calendar.OCTOBER, 31);
				Period period15 = createPeriod(year, Calendar.NOVEMBER, 1,
						Calendar.DECEMBER, 31);

				tempList.add(period11);
				tempList.add(perido12);
				tempList.add(period13);
				tempList.add(period14);
				tempList.add(period15);
				break;
			case 1:
				Period period16 = createPeriod(year, Calendar.JANUARY, 1,
						Calendar.JANUARY, 31);

				Period period17 = null;
				if (leapYear) {
					period17 = createPeriod(year, Calendar.FEBRUARY, 1,
							Calendar.FEBRUARY, 29);
				} else {
					period17 = createPeriod(year, Calendar.FEBRUARY, 1,
							Calendar.FEBRUARY, 28);
				}

				Period perido18 = createPeriod(year, Calendar.MARCH, 1,
						Calendar.MARCH, 31);
				Period period19 = createPeriod(year, Calendar.APRIL, 1,
						Calendar.APRIL, 30);
				Period period20 = createPeriod(year, Calendar.MAY, 1,
						Calendar.MAY, 31);
				Period period21 = createPeriod(year, Calendar.JUNE, 1,
						Calendar.JUNE, 30);
				Period period22 = createPeriod(year, Calendar.JULY, 1,
						Calendar.JULY, 31);
				Period period23 = createPeriod(year, Calendar.AUGUST, 1,
						Calendar.AUGUST, 31);
				Period period24 = createPeriod(year, Calendar.SEPTEMBER, 1,
						Calendar.SEPTEMBER, 30);
				Period period25 = createPeriod(year, Calendar.OCTOBER, 1,
						Calendar.OCTOBER, 31);
				Period period26 = createPeriod(year, Calendar.NOVEMBER, 1,
						Calendar.NOVEMBER, 30);
				Period period27 = createPeriod(year, Calendar.DECEMBER, 1,
						Calendar.DECEMBER, 31);

				tempList.add(period16);
				tempList.add(period17);
				tempList.add(perido18);
				tempList.add(period19);
				tempList.add(period20);
				tempList.add(period21);
				tempList.add(period22);
				tempList.add(period23);
				tempList.add(period24);
				tempList.add(period25);
				tempList.add(period26);
				tempList.add(period27);
				break;
			}
			return tempList;
		}
		return null;
	}

	/**
	 * Create a new period
	 * 
	 * @param year year
	 * @param monthStart start month
	 * @param dayStart start day
	 * @param monthEnd end month
	 * @param dayEnd end day
	 * @return the new period
	 */
	private Period createPeriod(int year, int monthStart, int dayStart,
			int monthEnd, int dayEnd) {
		Period period = new Period();

		Calendar start = Calendar.getInstance();
		Calendar end = Calendar.getInstance();

		start.set(year, monthStart, dayStart);
		end.set(year, monthEnd, dayEnd);

		period.setBeginOfPeriod(start);
		period.setEndOfPeriod(end);
		return period;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ch.zbw.timeline.service.YearConfigService#getAllPeriodsByYear(int)
	 */
	@Override
	public List<Period> getAllPeriodsByYear(int year) {

		List<YearConfig> tmpYearConfigList = yearConfigRepository
				.getAllYearConfigs();
		List<Period> tmpPeriodList = null;

		for (int i = 0; i < tmpYearConfigList.size(); i++) {
			if (tmpYearConfigList.get(i).getYear() == year) {
				tmpPeriodList = getAllPeriodsByYearConfig(tmpYearConfigList
						.get(i));
			}
		}
		return tmpPeriodList;
	}
}
